/**
 * 单页webapp MainWin对象
 */
/*global $win $config define window Base64 Test document Waiting History navigator iScroll :true*/
define([
    "jquery",
    "config",
    "topbar",
    "footer",
    "iscroll-probe",
    "hybrid_helper",
    "history",
    "ajax"
], function($, Config, Topbar, Footer, IScroll, HybridHelper) {
    function MainWin(width, height) {
        this.width = width;
        this.height = height;
        window.$config = new Config();
        window.Topbar = Topbar;
        window.Footer = Footer;
        this.topbar = new Topbar("header");
        this.topbar.initCommon();
        this.footer = new Footer("footer");
        this.footer.hide();

        this.container = null;
        this.errorDiv = null;
        // 页面跳转时的参数
        this.requestParams = null;

        // session
        this._session = {};

        // 框架内部调用方法
        this._jsCbMap = {};
        // proxy map
        this.hybridHelper = new HybridHelper();
        this.proxy = {};

        // 初始化
        this._init();

        /** 当前页面对象
         * initDom
         *  必填，初始化UI
         * initData
         *  必填，初始化数据，返回jqxhr对象，如果未返回则直接调用initEvent
         * initEvent
         *  必填，绑定页面事件，initData调用或者initData异步请求成功后200ms调用
         * beforeBackward
         *  选填，点击返回或者后退键之后、页面返回上一级之前调用
         *  如果返回true，表明此次后退事件已经被消费
         *  如果返回false或者不返回，则200ms之后判断是否可以后退，如果不可以则退出webView
         * beforeShowContent
         *  选填，展示页面内容前调用
         *      根据initData返回结果的情况，展示页面或者展示错误页面
         *      注意，如果实现该方法，必须在实现中手动调用$win.showContent()方法，否则不会展示页面内容
         *  如果不填，则直接展示页面
         */
        this._currentPage = {};

        this.scheme = "longtu";
        this._initSystem();
    }

    // -----------------------------------------------------------------------------------------------------------------------------------------------
    // 页面流转控制模块begin
    // -----------------------------------------------------------------------------------------------------------------------------------------------
    /**
     * MainWin初始化方法
     */
    MainWin.prototype._init = function() {
        // 处理statechange事件
        var me = this;
        me.container = $("[maincontainer=true]");
        me.container.addClass("mainContainer");
        me._initContainerSize();
        me.errorDiv = $("#mainErrorDiv");
        me.errorDiv.css("line-height", (this.height / 2) + "px");
        me.jsRegister("backward", me.backward);
        me.jsRegister("cancel", me.cancel);
        History.Adapter.bind(window, "statechange", function() {
            var state = History.getState();
            if (state.data.page) {
                me._showPage(state.data);
            }
        });
    };

    MainWin.prototype._initSystem = function() {
        if (typeof Test != "undefined" && Test) {
            this.getCustomScheme();
        }
    };

    MainWin.prototype.getCustomScheme = function() {
        if (typeof Test != "undefined" && Test) {
            this.scheme = Test.getCustomScheme();
        }
    };

    /**
     * 初始化container大小
     * container.height=mainwin.height-topbar.height-footer.height
     * container.width=mainwin.width
     * @return null
     */
    MainWin.prototype._initContainerSize = function() {
        this.container.width(this.width);
        this.container.height(this.height - this.topbar.getHeight() - this.footer.getHeight());
    };

    /**
     * 返回初始化时窗口大小
     */
    MainWin.prototype.getScreenSize = function() {
        return [this.width, this.height];
    };

    /**
     * 展示config中配置的首页
     */
    MainWin.prototype.loadHomepage = function() {
        if (!$.isNotBlank($config.homepage)) {
            $.MessageAlert({content: "未设定首页，请检查config.js"});
            return;
        }
        this.showPage($config.homepage.url, {
            moduleName: $config.homepage.moduleName
        }, false);
    };

    /**
     * 后退
     */
    MainWin.prototype.backward = function() {
        var invokeBack = this._currentPage.beforeBackward;
        if (invokeBack && typeof invokeBack == "function") {
            var consume = invokeBack.call(this._currentPage);
            if (consume) {
                return;
            }
        }
        var doBackward = function(result) {
            if (JSON.parse(result)) {
                History.back();
            } else {
                $win.cancel();
            }
        };
        this.getDefaultProxy().goBackward(doBackward);
    };

    /**
     * 前进
     */
    MainWin.prototype.forward = function() {
        History.forward();
    };

    /**
     * 展示页面
     * url:
     *      页面相对路径
     * params:
     *      网页加载参数，包括如下内置参数（关键字保留，不要占用）
     *          showTopbar: 是否显示topbar，默认是true
     *          moduleName: main.js中通过requireJS引入的module名，用于加载目标页面脚本
     *
     *          内部参数不要占用
     *          title: 页面标题，默认document.title
     *          page: 默认参数，页面相对路径
     *          sdata: 默认参数，时间戳，用于防止浏览器缓存
     *
     * cangoback:
     *      展示页面后是否允许后退到之前的页面
     *
     */
    MainWin.prototype.showPage = function(url, params, cangoback) {
        // 中断所有http请求
        $.abort();

        var page = url;
        params = $.extend({
            showTopbar: true
        }, params);
        url = $config.getUrl(url, params);
        params.page = page;
        params.sdata = new Date().getTime();
        var title = params.title
            ? params.title
            : document.title;
        if (cangoback == false) {
            History.replaceState(params, title, url);
        } else {
            History.pushState(params, title, url);
        }
    };

    /**
     * 内部函数，用于页面初始化前的窗口内容重置
     */
    MainWin.prototype._reset = function() {
        // 重置UI
        this.topbar.initCommon();
        this.footer.reset();
        $(".dw-modal").remove();
        $("#messagebox").remove();
        this.container.show();
        this.errorDiv.hide();
        // 重置当前页面
        this._currentPage = {};
        try{
            this.getDefaultProxy().releaseAudio();
        } catch(e){}
    };

    /**
     * 内部函数，展示页面
     */
    MainWin.prototype._showPage = function(data) {
        // 重置
        this._reset();
        // 设置参数
        this._saveParams(data);
        // 处理topbar和整体框架
        if (data.showTopbar) {
            $win.getTopbar().show();
            this.container.addClass("mainContainer");
        } else {
            $win.getTopbar().hide();
            this.container.removeClass("mainContainer");
        }
        this._initContainerSize();
        var _this = this;
        // 页面加载完成之前隐藏页面布局
        if (Waiting && Waiting.show) {
            Waiting.show();
        }
        this.hideContent();
        this.container.load($config.getLocation(data.page), function() {
            if ($.isNotBlank(data.moduleName)) {
                require([data.moduleName], function(PageModule) {
                    $win._currentPage = new PageModule(data);
                    if (_this._checkPageEvent()) {
                        var context = _this.getPageContext();
                        _this._currentPage.initDom.call(context);
                        var xhrArray = _this._currentPage.initData.call(context);
                        try {
                            if (xhrArray && $.isArray(xhrArray)) {
                                $.when.apply($, xhrArray).then(function() {
                                    // 成功
                                    setTimeout(function() {
                                        if (_this._currentPage.beforeShowContent && typeof _this._currentPage.beforeShowContent == "function") {
                                            _this._currentPage.beforeShowContent.call(context);
                                        } else {
                                            _this.showContent();
                                        }
                                        _this._currentPage.initEvent.call(context);
                                    }, 500);
                                }, function(e) {
                                    // 失败
                                    $win.log("initData执行失败，" + e.stack);
                                    _this.showErrorPage();
                                });
                            } else {
                                setTimeout(function() {
                                    if (_this._currentPage.beforeShowContent && typeof _this._currentPage.beforeShowContent == "function") {
                                        _this._currentPage.beforeShowContent.call(context);
                                    } else {
                                        _this.showContent();
                                    }
                                    _this._currentPage.initEvent.call(context);
                                }, 500);
                            }
                        } catch (e) {
                            $win.log("initData后续错误：" + e.stack);
                            _this.showErrorPage();
                        }
                    } else {
                        $win.log("页面未注册initDom,initData,initEvent函数");
                        _this.backward();
                    }
                });
            }
        });
    };

    /**
     * 展示默认错误页面
     */
    MainWin.prototype.showErrorPage = function() {
        if (Waiting && Waiting.show) {
            Waiting.hide();
        }
        this.container.hide();
        this.errorDiv.show();
        this.errorDiv.click(function() {
            $win.refresh();
        });
    };

    /**
     * 隐藏页面内容
     */
    MainWin.prototype.hideContent = function() {
        this.container.addClass("ml100");
    };

    /**
     * 展示页面内容
     */
    MainWin.prototype.showContent = function() {
        if (Waiting && Waiting.show) {
            Waiting.hide();
        }
        this.container.removeClass("ml100");
        this.errorDiv.hide();
    };

    /**
     * 刷新当前页面
     */
    MainWin.prototype.refresh = function() {
        var url = this.requestParams.page;
        var params = $.extend({}, this.requestParams);
        delete params.page;
        this.showPage(url, params, false);
    };

    /**
     * 获取当前的页面对象
     */
    MainWin.prototype.getPageContext = function() {
        return this._currentPage;
    };

    /**
     * 获取参数
     */
    MainWin.prototype.getParams = function() {
        return this.requestParams;
    };

    /**
     * 内部方法，保存页面参数
     */
    MainWin.prototype._saveParams = function(data) {
        this.requestParams = data;
    };

    /**
     * 内部函数，用于检测页面对象是否实现了必须的方法
     */
    MainWin.prototype._checkPageEvent = function() {
        return $.isFunc(this._currentPage.initDom) && $.isFunc(this._currentPage.initData) && $.isFunc(this._currentPage.initEvent);
    };

    /**
     * 打开新的webview窗口
     * page:
     *      新页面地址
     * params:
     *      新页面参数
     *          showTopbar: 是否显示topbar，默认是true
     *          moduleName: main.js中通过requireJS引入的module名，用于加载目标页面脚本
     *
     *          内置参数
     *          project: 目标页面所在项目，默认当前项目由$config.project配置
     *          pageType: 页面类型, 0表示内置页面，1表示外链，默认0
     *          showNativeTopbar: 是否展示webview的系统默认topbar，默认false
     *          nativeTitle: webview的系统默认topbar的title
     *
     * callback:
     *      新页面关闭时执行的回调，接受JSON对象作为参数，参见cancel方法
     *
     * 注意
     *      每个窗口中的全局变量是不通用的，对于全局变量的修改不会刷新到其他win，需要手动刷新
     *      比如在newWin中修改了登录用户信息，返回原始窗口的时候需要重新更新登录用户信息
     *
     */
    MainWin.prototype.showNewWin = function(page, params, callback) {
        params = $.extend({
            showTopbar: true
        }, params);

        var pageTypeStr = (params.pageType == 1)
            ? "TYPE_OUTLINK"
            : "TYPE_INNERLINK";
        var nativeTopbar = params.showNativeTopbar || false;
        var nativeTitle = params.nativeTitle || "";
        var project = params.project || $config.project;
        delete params.nativeTitle;
        delete params.showNativeTopbar;
        delete params.pageType;
        delete params.project;

        var urlParam = {
            "project": project,
            "page": page,
            "params": JSON.stringify(params),
            "type_tag": pageTypeStr,
            "native_topbar": nativeTopbar,
            "title": nativeTitle
        };
        this.getDefaultProxy().showNewWin(urlParam, callback);
    };

    /**
     * 退出webview
     */
    MainWin.prototype.cancel = function(data) {
        data = data || {};
        this.getDefaultProxy().cancel(data);
    };

    /**
     * 退出所有打开的webview，只剩余堆栈底部的
     */
    MainWin.prototype.cancelAll = function(data) {
        data = data || {};
        this.getDefaultProxy().cancelAll(data);
    };
    // -----------------------------------------------------------------------------------------------------------------------------------------------
    // 页面流转控制模块end
    // -----------------------------------------------------------------------------------------------------------------------------------------------

    // -----------------------------------------------------------------------------------------------------------------------------------------------
    // 通用辅助方法begin
    // -----------------------------------------------------------------------------------------------------------------------------------------------
    /**
     * 保存全局参数
     */
    MainWin.prototype.setSession = function(key, value) {
        if (value == null || typeof value == "undefined") {
            if (this._session.hasOwnProperty(key)) {
                delete this._session[key];
            }
        } else {
            this._session[key] = value;
        }
    };

    /**
     * 获取全局参数
     */
    MainWin.prototype.getSession = function(key) {
        return this._session[key];
    };

    /**
     * 获取页面topbar对象
     */
    MainWin.prototype.getTopbar = function() {
        return this.topbar;
    };

    /**
     * 手势支持
     *
     * @param elem
     * @param options
     * @returns {iScroll}
     */
    MainWin.prototype.touchScroll = function(elem, options) {
        if (typeof(elem) == "object") {
            elem = elem[0];
        }
        var defaultOptions = {};
        defaultOptions.momentum = true;
        defaultOptions.handleClick = false;
        defaultOptions.useTransition = this._isTransition();
        if (/iphone/.test(navigator.userAgent.toLowerCase())) {
            defaultOptions.useTransition = true;
        }
        defaultOptions.checkDOMChanges = false;
        defaultOptions.hideScrollbar = true;
        defaultOptions.scrollbarClass = "myScrollbar";

        defaultOptions.onBeforeScrollStart = function(e) {
            if (this.absDistX > (this.absDistY + 5)) {
                e.preventDefault();
            }
            var target = e.target;
            while (target.nodeType != 1) {
                target = target.parentNode;
            }
            if (target.tagName != "SELECT" && target.tagName != "INPUT" && target.tagName != "TEXTAREA") {
                e.preventDefault();
            }
            //e.stopPropagation();
        };
        defaultOptions.onScrollMove = function(e) {
            var x = e.x;
            var y = e.y;
            if (Math.abs(x - this._startx) > 10 || Math.abs(y - this._starty) > 10) {
                $(e.target).prop("data-click", "n");
            } else {
                $(e.target).prop("data-click", "y");
            }
        };
        defaultOptions.onTouchEnd = function() {
            var self = this;
            if (self.touchEndTimeId) {
                clearTimeout(self.touchEndTimeId);
            }
            self.touchEndTimeId = setTimeout(function() {
                self.absDistX = 0;
                self.absDistY = 0;
            }, 600);
        };
        options = $.extend(defaultOptions, options);

        // 强制设置android机器的useTransition为false，以修正个别手机webview上对于topbar的兼容性问题
        // 暂时没有办法分辨手机兼容性，不使用transition会导致滚动性能降低
        if (/iphone/.test(navigator.userAgent.toLowerCase())) {
            options.useTransition = true;
        } else {
            options.useTransition = false;
        }

        return new iScroll(elem, options);
    };

    MainWin.prototype._isTransition = function() {
        var dummyStyle = document.createElement("div").style;
        var vendors = "t,webkitT,MozT,msT,OT".split(","),
            t,
            i = 0,
            l = vendors.length;
        var temp = null;
        for (; i < l; i++) {
            t = vendors[i] + "ransform";
            if (t in dummyStyle) {
                temp = vendors[i].substr(0, vendors[i].length - 1);
                break;
            }
        }
        if (temp && temp == "") {
            return false;
        } else {
            return true;
        }
    };

    /**
     * 使用iScroll5管理页面滚动，默认配置兼容移动端和浏览器
     * 使用$win.touchScroll5("#id")
     * @author Keith
     */
    MainWin.prototype.touchScroll5 = function(elem, options) {
        if (typeof(elem) == "object") {
            elem = elem[0];
        }
        // 处理滚动手势
        options = options || {};
        // 惯性
        options.momentum = true; // 允许有惯性滑动
        options.click = true;
        options.probeType = 1;
        options.bounce = true; //边界反弹
        options.shrinkScrollbars = "scale"; // 当滚动边界之外的滚动条是由少量的收缩。'clip' or 'scale'.
        options.mouseWheel = true, // 是否监听鼠标滚轮事件。
        options.scrollbars = false, // 是否显示默认滚动条
        options.fadeScrollbars = true, // 是否渐隐滚动条，关掉可以加速
        options.useTransition = this._isTransition();
        if (/iphone/.test(navigator.userAgent.toLowerCase())) {
            options.useTransition = true;
        }
        return new IScroll(elem, options);
    };

    /**
     * 调用android本地js绑定实现内容保存
     */
    MainWin.prototype.setCookie = function(key, value) {
        if (typeof Test != "undefined" && Test) {
            Test.setCookie(key, value);
        }
    };

    /**
     * 获取通过setCookie保存的内容
     */
    MainWin.prototype.getCookie = function(key) {
        var result = null;
        if (typeof Test != "undefined" && Test) {
            result = Test.getCookie(key);
        }
        return result;
    };

    /**
     * 调用js绑定输出日志
     */
    MainWin.prototype.log = function(text) {
        if (typeof Test == "undefined" || null == Test || typeof Test.log != "function") {
            console.log(text);
            return;
        }
        Test.log(text);
    };

    /**
     * 根据本地文件路径，返回可以被页面展示的文件链接
     * 常用于拍照或选取图片之后页面展示图片预览
     */
    MainWin.prototype.getLocalFileUri = function(path) {
        path = path.replace("\\/", "/");
        return "localfile?src=" + Base64.encode(path) + "&_t=" + (new Date().getTime());
    };

    /**
     * 获取当前版本号
     * 返回
     *      version_name    文件版本号
     *      version_code    数字版本号
     */
    MainWin.prototype.getVersionInfo = function() {
        // 注意 该方法需要iOS单独实现
        if (typeof Test != "undefined" && Test) {
            return Test.getVersionInfo();
        }

        return {};
    };

    //=========================================
    // 代理与交互
    //=========================================
    MainWin.prototype.initProxy = function() {
        require(["../../common/scripts/lib/hybrid/default.proxy"],function(DefaultProxy) {
            $win.proxy["default"] = new DefaultProxy($win.scheme, $win.hybridHelper);
        });
        // 加载自定义代理
        for(var i = 0; i != $config.proxyList.length; i++) {
            var proxy = $config.proxyList[i];
            if(proxy.hasOwnProperty("name") && proxy.hasOwnProperty("path")) {
                require([proxy.path],function(Proxy) {
                    $win.proxy[proxy.name] = new Proxy($win.scheme, $win.hybridHelper);
                });
            }
        }
    };

    MainWin.prototype.getProxy = function(name) {
        return this.proxy[name];
    };

    MainWin.prototype.getDefaultProxy = function() {
        return this.proxy["default"];
    };

    // 不推荐使用
    MainWin.prototype.executeProxy = function(proxy, method, params, callback) {
        this.hybridHelper.proxyExecute(this.scheme, proxy, method, params, callback);
    };

    MainWin.prototype.callbackProxy = function(proxy, method, params) {
        this.hybridHelper.proxyCallback(proxy, method, params);
    };

    // js-binding全局辅助功能函数
    MainWin.prototype.jsRegister = function(key, callback) {
        if(this._jsCbMap.hasOwnProperty(key)) {
            delete this._jsCbMap[key];
        }
        if(typeof callback != "undefined" && callback != null) {
            this._jsCbMap[key] = callback;
        }
    };

    MainWin.prototype.jsCallback = function(key, params) {
        if(this._jsCbMap.hasOwnProperty(key)) {
            var cb = this._jsCbMap[key];
            cb.call(this, params);
            // backward是系统事件，不需要重置
            if(key != "backward") {
                this.jsRegister(key);
            }
        } else {
            this.log("事件" + key + "未注册。");
        }
    };

    return MainWin;
});
